package com.law.lawcaculator.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.googlecode.aviator.AviatorEvaluator;
import com.law.lawcaculator.mapper.*;
import com.law.lawcaculator.model.dto.GenerateReportResponse;
import com.law.lawcaculator.model.entity.*;
import com.law.lawcaculator.service.AdvancedReportService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.stream.Collectors;

import jakarta.servlet.http.HttpServletResponse;

@Service
@RequiredArgsConstructor
@Slf4j
public class AdvancedReportServiceImpl implements AdvancedReportService {

    private final ReportSessionsMapper reportSessionsMapper;
    private final QuestionOptionsMapper questionOptionsMapper;
    private final QuestionsMapper questionsMapper;
    private final ItemTemplateMapper itemTemplateMapper;
    private final CalculationRulesMapper calculationRulesMapper;
    private final ItemSectionMappingMapper itemSectionMappingMapper;
    private final ReportSectionsMapper reportSectionsMapper;
    private final ReportLayoutMapper reportLayoutMapper;
    private final RegionConfigsMapper regionConfigsMapper;
    private final CalculatorTemplateMappingsMapper calculatorTemplateMappingsMapper;

    @Override
    public GenerateReportResponse generateDetailedReport(String sessionId, List<SubmitAnswers> answers, String appId) {
        try {
            // 1. 处理answers，构建选项和问题的映射关系
            Map<String, String> optionNumberValueMap = new HashMap<>();
            Map<String, Object> questionNumberValueMap = new HashMap<>();

            // 批量获取所有需要的问题和选项ID
            Set<Long> questionIds = new HashSet<>();
            Set<Long> optionIds = new HashSet<>();
            
            for (SubmitAnswers answer : answers) {
                if (answer.getQuestionId() != null) {
                    questionIds.add(answer.getQuestionId());
                }
                if (answer.getOptionId() != null) {
                    optionIds.add(answer.getOptionId());
                }
            }

            // 批量查询问题和选项信息
            List<Questions> questionsList = questionsMapper.selectList(
                    new LambdaQueryWrapper<Questions>().in(Questions::getQId, questionIds));
            List<QuestionOptions> optionsList = questionOptionsMapper.selectList(
                    new LambdaQueryWrapper<QuestionOptions>().in(QuestionOptions::getOId, optionIds));

            // 构建ID到对象的映射，方便快速查找
            Map<Long, Questions> questionMap = questionsList.stream()
                    .collect(Collectors.toMap(Questions::getQId, q -> q));
            Map<Long, QuestionOptions> optionMap = optionsList.stream()
                    .collect(Collectors.toMap(QuestionOptions::getOId, o -> o));

            // 3. 处理每个answer，构建映射
            for (SubmitAnswers answer : answers) {
                String value = answer.getAnswer();
                
                // 情况1：有选项ID，表示选中了某个选项
                if (answer.getOptionId() != null) {
                    QuestionOptions option = optionMap.get(answer.getOptionId());
                    if (option != null) {
                        optionNumberValueMap.put(option.getONumber(), value != null ? value : "true");
                    }
                }
                // 情况2：有问题ID，表示在某个问题的输入框填写了内容
                else if (answer.getQuestionId() != null) {
                    Questions question = questionMap.get(answer.getQuestionId());
                    if (question != null) {
                        // 特殊处理地域问题
                        if (answer.isRegion() && value != null) {
                            // 获取地域配置信息
                            RegionConfigs regionConfig = getRegionConfigByValue(value);
                            if (regionConfig != null && regionConfig.getConfig() instanceof Map) {
                                Map<String, Object> configMap = (Map<String, Object>) regionConfig.getConfig();
                                questionNumberValueMap.put(question.getQNumber(), configMap);
                            } else {
                                questionNumberValueMap.put(question.getQNumber(), value);
                            }
                        } else {
                            questionNumberValueMap.put(question.getQNumber(), value);
                        }
                    }
                }
            }

            // 4. 合并两个map的键，查询对应的item
            Set<String> allKeys = new HashSet<>();
            allKeys.addAll(optionNumberValueMap.keySet());
            allKeys.addAll(questionNumberValueMap.keySet());

            // 查询与这些key相关的item模板
            List<ItemTemplate> itemTemplates = findItemTemplatesByKeys(allKeys);

            // 5. 处理每个item的规则计算和模板替换
            Map<Long, String> renderedItemMap = new HashMap<>();
            Map<String, Object> calculationContext = new HashMap<>();
            
            // 将option和question的map合并到计算上下文中
            calculationContext.putAll(optionNumberValueMap);
            calculationContext.putAll(questionNumberValueMap);

            for (ItemTemplate itemTemplate : itemTemplates) {
                // 获取item对应的计算规则
                String renderedContent = processItemTemplate(itemTemplate, calculationContext);
                renderedItemMap.put(itemTemplate.getId(), renderedContent);
            }

            // 6. 查询app对应的layout和section信息
            ReportLayout layout = getLayoutByAppId(appId);
            List<ReportSections> sections = getSectionsByLayout(layout);

            // 7. 根据item_section_mapping将item按section分组
            Map<String, List<Long>> sectionItemMap = getItemSectionMapping(sections);

            // 8. 组装每个section的内容
            Map<String, String> sectionContentMap = new HashMap<>();
            for (ReportSections section : sections) {
                List<Long> itemIds = sectionItemMap.getOrDefault(section.getSectionCode(), Collections.emptyList());
                String sectionContent = assembleSectionContent(section, itemIds, renderedItemMap);
                sectionContentMap.put(section.getSectionCode(), sectionContent);
            }

            // 9. 根据layout布局配置合并所有section
            String finalHtmlReport = mergeSectionsToFinalReport(layout, sectionContentMap);

            // 10. 保存会话数据
            saveReportSession(sessionId, answers, calculationContext, finalHtmlReport);

            return new GenerateReportResponse(sessionId, finalHtmlReport);
            
        } catch (Exception e) {
            log.error("Failed to generate detailed report for session: {}", sessionId, e);
            throw new RuntimeException("Report generation failed", e);
        }
    }

    @Override
    public void downloadWordReport(String sessionId, HttpServletResponse response) {
        try {
            // 复用现有的下载逻辑
            ReportSessions session = reportSessionsMapper.selectOne(
                    new LambdaQueryWrapper<ReportSessions>().eq(ReportSessions::getSessionId, sessionId));
            
            if (session == null || session.getHtmlContent() == null) {
                throw new RuntimeException("Report session not found or content missing");
            }
            
            // 设置响应头
            response.setContentType("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
            response.setHeader("Content-Disposition", "attachment; filename=detailed_report_" + sessionId + ".docx");
            
            // 创建Word文档
            org.apache.poi.xwpf.usermodel.XWPFDocument document = new org.apache.poi.xwpf.usermodel.XWPFDocument();
            
            // 处理HTML内容，创建段落
            org.apache.poi.xwpf.usermodel.XWPFParagraph paragraph = document.createParagraph();
            org.apache.poi.xwpf.usermodel.XWPFRun run = paragraph.createRun();
            
            // 简化的HTML处理 - 在实际项目中，应该使用更专业的HTML到Word转换库
            // 这里只是示例，实际项目中需要引入如docx4j或openhtmltopdf等库进行完整的HTML转换
            String plainText = extractPlainTextFromHtml(session.getHtmlContent());
            run.setText(plainText);
            
            // 写入响应流
            try (java.io.OutputStream out = response.getOutputStream()) {
                document.write(out);
            }
            
            document.close();
            
        } catch (Exception e) {
            log.error("Failed to download detailed Word report for session: {}", sessionId, e);
            throw new RuntimeException("Detailed report download failed", e);
        }
    }
    
    /**
     * 从HTML中提取纯文本
     */
    private String extractPlainTextFromHtml(String html) {
        // 简单的HTML去除标签逻辑
        String text = html.replaceAll("<[^>]*>", "");
        // 去除多余的空白字符
        text = text.replaceAll("\\s+", " ");
        return text.trim();
    }

    /**
     * 根据keys查询相关的item模板
     */
    private List<ItemTemplate> findItemTemplatesByKeys(Set<String> keys) {
        // 这里需要实现根据optionNumbers和questionNumbers查询item模板的逻辑
        // 由于ItemTemplate中的字段是Object类型，可能需要更复杂的查询逻辑
        return itemTemplateMapper.selectList(null).stream()
                .filter(item -> {
                    // 简化实现，实际应该检查item的optionsNumbers或questionsNumbers是否与keys匹配
                    return true;
                })
                .collect(Collectors.toList());
    }

    /**
     * 处理单个item模板，执行规则计算并替换模板
     */
    private String processItemTemplate(ItemTemplate itemTemplate, Map<String, Object> context) {
        String contentTemplate = itemTemplate.getContentTemplate();
        if (contentTemplate == null) {
            return "";
        }

        // 如果item关联了计算规则，先执行规则计算
        if (itemTemplate.getRuleId() != null) {
            CalculationRules rule = calculationRulesMapper.selectById(itemTemplate.getRuleId());
            if (rule != null && rule.getCalculationExpression() != null) {
                try {
                    Object result = AviatorEvaluator.execute(rule.getCalculationExpression(), context);
                    String outputKey = rule.getOutputKey();
                    if (outputKey != null) {
                        context.put(outputKey, result);
                    }
                } catch (Exception e) {
                    log.error("Failed to execute rule: {}", rule.getRuleName(), e);
                }
            }
        }

        // 替换模板中的占位符
        return replaceTemplatePlaceholders(contentTemplate, context);
    }

    /**
     * 替换模板中的占位符
     */
    private String replaceTemplatePlaceholders(String template, Map<String, Object> context) {
        String result = template;
        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("\\$\\{([^\\}]+)\\}");
        java.util.regex.Matcher matcher = pattern.matcher(template);

        while (matcher.find()) {
            String varName = matcher.group(1);
            Object value = context.getOrDefault(varName, "");
            result = result.replace("${" + varName + "}", value.toString());
        }

        return result;
    }

    /**
     * 根据appId获取对应的layout
     */
    private ReportLayout getLayoutByAppId(String appId) {
        // 先通过calculator_template_mappings查询对应的模板ID
        CalculatorTemplateMappings mapping = calculatorTemplateMappingsMapper.selectOne(
                new LambdaQueryWrapper<CalculatorTemplateMappings>().eq(CalculatorTemplateMappings::getAppId, Long.valueOf(appId)));
        
        if (mapping != null && mapping.getTemplateId() != null) {
            // 使用模板ID查询布局（这里假设templateId和layout的id关联）
            return reportLayoutMapper.selectById(mapping.getTemplateId());
        }
        
        // 如果没有找到，返回默认的激活的layout
        return reportLayoutMapper.selectOne(
                new LambdaQueryWrapper<ReportLayout>().eq(ReportLayout::getIsActive, 1));
    }

    /**
     * 根据layout获取所有section
     */
    private List<ReportSections> getSectionsByLayout(ReportLayout layout) {
        if (layout == null || layout.getSectionConfig() == null) {
            return reportSectionsMapper.selectList(null);
        }
        
        // 假设sectionConfig是包含sectionCode列表的对象
        try {
            Map<String, Object> sectionConfig = (Map<String, Object>) layout.getSectionConfig();
            List<String> sectionCodes = (List<String>) sectionConfig.get("sections");
            
            if (sectionCodes != null && !sectionCodes.isEmpty()) {
                return reportSectionsMapper.selectList(
                        new LambdaQueryWrapper<ReportSections>()
                                .in(ReportSections::getSectionName, sectionCodes)
                                .orderByAsc(ReportSections::getSortOrder));
            }
        } catch (Exception e) {
            log.error("Failed to parse section config", e);
        }
        
        return reportSectionsMapper.selectList(null);
    }

    /**
     * 获取item和section的映射关系
     */
    private Map<String, List<Long>> getItemSectionMapping(List<ReportSections> sections) {
        List<String> sectionNames = sections.stream()
                .map(ReportSections::getSectionName)
                .toList();
        
        List<ItemSectionMapping> mappings = itemSectionMappingMapper.selectList(
                new LambdaQueryWrapper<ItemSectionMapping>()
                        .in(ItemSectionMapping::getSectionName, sectionNames));
        
        return mappings.stream()
                .collect(Collectors.groupingBy(
                        ItemSectionMapping::getSectionName,
                        Collectors.mapping(ItemSectionMapping::getItemId, Collectors.toList())
                ));
    }

    /**
     * 组装单个section的内容
     */
    private String assembleSectionContent(ReportSections section, List<Long> itemIds, Map<Long, String> renderedItemMap) {
        StringBuilder content = new StringBuilder();
        
        // 添加section标题
        content.append("<h2>").append(section.getSectionName()).append("</h2>");
        
        // 添加每个item的内容
        for (Long itemId : itemIds) {
            String itemContent = renderedItemMap.get(itemId);
            if (itemContent != null) {
                content.append("<div class='item'>").append(itemContent).append("</div>");
            }
        }
        
        // 如果section有内容模板，应用模板
        if (section.getContentTemplate() != null) {
            Map<String, Object> context = new HashMap<>();
            context.put("sectionContent", content.toString());
            return replaceTemplatePlaceholders(section.getContentTemplate(), context);
        }
        
        return content.toString();
    }

    /**
     * 根据layout布局配置合并所有section
     */
    private String mergeSectionsToFinalReport(ReportLayout layout, Map<String, String> sectionContentMap) {
        StringBuilder finalReport = new StringBuilder();
        
        // 添加HTML头部
        finalReport.append("<!DOCTYPE html>");
        finalReport.append("<html><head><meta charset='UTF-8'><title>法律计算报告</title></head><body>");
        
        // 根据layoutConfig中的顺序组装section
        if (layout != null && layout.getLayoutConfig() != null) {
            try {
                Map<String, Object> layoutConfig = (Map<String, Object>) layout.getLayoutConfig();
                List<String> sectionOrder = (List<String>) layoutConfig.get("sectionOrder");
                
                if (sectionOrder != null) {
                    for (String sectionCode : sectionOrder) {
                        String content = sectionContentMap.get(sectionCode);
                        if (content != null) {
                            finalReport.append(content);
                        }
                    }
                }
            } catch (Exception e) {
                log.error("Failed to parse layout config", e);
            }
        }
        
        // 如果没有配置，按默认顺序添加所有section
        if (finalReport.indexOf("<h2>") == -1) {
            sectionContentMap.values().forEach(finalReport::append);
        }
        
        finalReport.append("</body></html>");
        return finalReport.toString();
    }

    /**
     * 根据地域值获取地域配置
     */
    private RegionConfigs getRegionConfigByValue(String regionValue) {
        return regionConfigsMapper.selectOne(
                new LambdaQueryWrapper<RegionConfigs>()
                        .and(qw -> qw.eq(RegionConfigs::getRegionName, regionValue)
                                .or().eq(RegionConfigs::getRegionCode, regionValue))
                        .eq(RegionConfigs::getIsActive, 1));
    }

    /**
     * 保存详细报告会话数据到数据库
     * @param sessionId 会话ID
     * @param answers 用户提交的答案列表
     * @param calculationResults 计算结果上下文
     * @param htmlContent HTML报告内容
     */
    private void saveReportSession(String sessionId, List<SubmitAnswers> answers, 
                                 Map<String, Object> calculationResults, String htmlContent) {
        // 数据验证
        if (sessionId == null || sessionId.trim().isEmpty()) {
            throw new IllegalArgumentException("会话ID不能为空");
        }
        
        if (answers == null) {
            answers = new ArrayList<>();
            log.warn("答案列表为空，使用空列表代替");
        }
        
        if (calculationResults == null) {
            calculationResults = new HashMap<>();
            log.warn("计算结果为空，使用空Map代替");
        }
        
        if (htmlContent == null || htmlContent.trim().isEmpty()) {
            htmlContent = "<html><head><meta charset='UTF-8'><title>法律计算报告</title></head><body><h1>法律计算报告</h1><p>无数据</p></body></html>";
            log.warn("HTML内容为空，使用默认内容代替");
        }
        
        try {
            ReportSessions session = new ReportSessions();
            session.setSessionId(sessionId);
            // 设置计算器编码，使用默认值"DEFAULT_CALCULATOR"
            // 后续可以根据业务需求从请求或上下文中获取实际的计算器编码
            session.setCalculatorCode("DEFAULT_CALCULATOR");
            session.setUserAnswers(answers);
            session.setCalculationResults(calculationResults);
            // 限制HTML内容长度，防止过长
            if (htmlContent.length() > 100000) {
                htmlContent = htmlContent.substring(0, 100000) + "...<p>内容过长，已截断</p></body></html>";
                log.warn("HTML内容过长，已截断");
            }
            session.setHtmlContent(htmlContent);
            session.setCreatedTime(new Date());
            session.setExpiresTime(Date.from(LocalDateTime.now().plusDays(7).toInstant(ZoneOffset.UTC)));
            
            // 先尝试更新，如果不存在则插入
            ReportSessions existing = reportSessionsMapper.selectOne(
                    new LambdaQueryWrapper<ReportSessions>().eq(ReportSessions::getSessionId, sessionId));
            
            if (existing != null) {
                session.setId(existing.getId());
                reportSessionsMapper.updateById(session);
                log.info("更新详细报告会话: {}", sessionId);
            } else {
                reportSessionsMapper.insert(session);
                log.info("保存新的详细报告会话: {}", sessionId);
            }
        } catch (Exception e) {
            log.error("保存详细会话数据失败，会话ID: {}", sessionId, e);
            // 包装异常，提供更明确的错误信息
            throw new RuntimeException("保存详细报告会话数据失败，请稍后重试", e);
        }
    }
}